﻿namespace MathVisualizer


module Render =
    open System.Drawing
    open System.Drawing.Drawing2D 
    open MathVisualizer.DrawLibrary 
    open MathVisualizer.UserControls 
    open MathVisualizer.Utils 
    let rec paintTree(g:Graphics, offset:PointF, node:Expr, level, _minfo:mouseInfo) = 
        let mutable minfo = _minfo
        g.SmoothingMode <- System.Drawing.Drawing2D.SmoothingMode.AntiAlias 
        node.Offset <- offset
        let drawRectangle = new RectangleF(offset.X + node.Box.X, offset.Y + node.Box.Y, node.Box.Width, node.Box.Height)
        //let drawContainer = new RectangleF(offset.X, offset.Y, node.Container.Width, node.Container.Height)
        match node.Expr with 
        |BigSum(p1, p2, arg) | Integral(p1, p2, arg) | Union(p1, p2, arg) | Intersection(p1, p2, arg) | Productor(p1, p2, arg)->
            let gp = match node.Expr with
                        |BigSum(_, _, _) -> SumSymbol(drawRectangle)
                        |Integral(_, _, _) -> IntegralSymbol(drawRectangle)
                        |Union(_, _, _) -> UnionIntersectSymbol(drawRectangle, 1.f)
                        |Intersection(_, _, _) -> UnionIntersectSymbol(drawRectangle, -1.f)
                        |Productor(_, _, _) -> productorSymbol(drawRectangle)
                        | _ -> new GraphicsPath()

            drawPath g gp
            //g.DrawString(symbol, font(level, true), Brushes.Black, drawRectangle)
            paintTree(g, cdr(p1, offset), p1, level+1, minfo)
            paintTree(g, cdr(p2, offset), p2, level+1, minfo)
            paintTree(g, cdr(arg, offset), arg, level, minfo)
        |Sum(e1, e2) | Sub(e1, e2) | Equals(e1, e2) | Concat(e1, e2) | LeftArrow(e1, e2) | RightArrow(e1, e2) | Major(e1, e2)
        |Minor(e1, e2) |Geq(e1, e2) |Leq(e1, e2) |Approx(e1, e2) | Mul(e1, e2) ->
            let symbol = match node.Expr with
                                |Sum(e1, e2) -> "+"
                                |Sub(e1, e2) -> "-"
                                |Equals(e1, e2) -> "="
                                |Concat(e1, e2) -> ""
                                |Major(e1, e2) -> ">"
                                |Minor(e1, e2) -> "<"
                                |Geq(e1, e2) -> "\u2265"
                                |Leq(e1, e2) -> "\u2264"
                                |Approx(e1, e2) -> "\u2248"
                                |Mul(e1, e2) -> "*"
                                | _ -> ""

            match node.Expr with
                |LeftArrow(_, _) -> drawPath g (arrowSymbol(drawRectangle, -1.f))
                |RightArrow(_, _) ->drawPath g (arrowSymbol(drawRectangle, 1.f))
                | _ -> g.DrawString(symbol, font(level, false), Brushes.Black, drawRectangle)
            
            paintTree(g, cdr(e1, offset), e1, level, minfo)
            paintTree(g, cdr(e2, offset), e2, level, minfo)
        |Ratio(e1, e2) ->
            paintTree(g, cdr(e1, offset), e1, level, minfo)
            paintTree(g, cdr(e2, offset), e2, level, minfo)
            let lineY = int(offset.Y + e1.Container.Y + e1.Container.Height + 3.f)
            let startx = offset.X + 1.f
            //debug "PAINTING RATIO"
            g.DrawLine(Pens.Black, new Point(int startx, lineY), new Point(int (startx + node.Container.Width - 1.f), lineY))
        |Exponent(e1, e2) | Subscript(e1, e2) ->
            paintTree(g, cdr(e1, offset), e1, level, minfo)
            paintTree(g, cdr(e2, offset), e2, level+1, minfo)
        |Round(e) | Square(e) | Brace(e) | Group(e) ->
            let drawRectangle2 = new RectangleF(drawRectangle.X + drawRectangle.Width*2.f + e.Container.Width, drawRectangle.Y, drawRectangle.Width, drawRectangle.Height)
            let f = new Font(stdfont, e.Container.Height)
            let mutable isgroup = false;
            let gopen, gclose = match node.Expr with
                                |Round(e) -> round(drawRectangle, 1.f), round(drawRectangle2, -1.f)
                                |Square(e) -> square(drawRectangle, 1.f), square(drawRectangle2, -1.f)
                                |Brace(e) -> brace(drawRectangle, 1.f), brace(drawRectangle2, -1.f)
                                | _ -> isgroup <- true; new GraphicsPath(), new GraphicsPath() 
            
            if not isgroup then
                drawPath g gopen
                drawPath g gclose

            paintTree(g, cdr(e, offset), e, level, minfo)
            ()
        |Matrix(rows, cols, els) ->
            let a = ref minfo

            Array.iter(fun (x:Expr) -> 
                            paintTree(g, cdr(x, offset), x, level + 1, !a)
                                  
                      )els

            ()
        |Sqrt(exp, rad) ->
            paintTree(g, cdr(exp, offset), exp, level+1, minfo)
            paintTree(g, cdr(rad, offset), rad, level, minfo)
            let gp = sqrtSymbol(drawRectangle)
            drawPath g gp
            let linex = drawRectangle.X + drawRectangle.Width
            
            g.DrawLine(Pens.Black, PointF(linex, drawRectangle.Y), PointF(linex + rad.Container.Width, drawRectangle.Y))

            ()
        |Limit(p1, arg) ->
            paintTree(g, cdr(p1, offset), p1, level+1, minfo)
            paintTree(g, cdr(arg, offset), arg, level, minfo)

            g.DrawString("lim", font(level, false), Brushes.Black, drawRectangle)
        |Literal(str) ->
            g.DrawString(str, font(level, false), Brushes.Black, drawRectangle)

        | _ -> ()
    
    
        if node.MouseOver then g.DrawRectangle(Pens.Black, Rectangle.Round(node.DrawContainer))
        if node.Clicked then 
            g.DrawRectangle(Pens.BlueViolet, Rectangle.Round(node.DrawContainer))
            g.FillRectangle(new SolidBrush(Color.FromArgb(60, Color.Blue)), Rectangle.Round(node.DrawContainer))
        ()
